#version 430 core

#define BLOCK_SIZE 512

layout(local_size_x=BLOCK_SIZE) in;

layout(binding=0) coherent buffer inVector1Buffer
{
	float inVector1[];
};

layout(binding=1) coherent buffer inVector2Buffer
{
	float inVector2[];
};

layout(binding=2) coherent buffer outVectorBuffer
{
	float outVector[];
};

uniform uint n;

shared float sData[BLOCK_SIZE];

void main(void)
{
	uint lid = gl_LocalInvocationID.x;
	uint i = gl_WorkGroupID.x * (BLOCK_SIZE*2) + lid;
	uint gridSize = BLOCK_SIZE * 2 * gl_NumWorkGroups.x;
	sData[lid] = 0.0;

	while (i<n)
	{
		sData[lid] += inVector1[i]*inVector2[i];
		if (i+BLOCK_SIZE < n)
			sData[lid] += inVector1[i+BLOCK_SIZE]*inVector2[i+BLOCK_SIZE];
		i += gridSize;
	}

	memoryBarrierShared();
	barrier();

#if (BLOCK_SIZE >= 512)
	if (lid < 256)
	{
		sData[lid] += sData[lid+256];
		memoryBarrierShared();
		barrier();
	}
#endif

#if (BLOCK_SIZE >= 256)
	if (lid < 128)
	{
		sData[lid] += sData[lid+128];
		memoryBarrierShared();
		barrier();
	}
#endif

#if (BLOCK_SIZE >= 128)
	if (lid < 64)
	{
		sData[lid] += sData[lid+64];
		memoryBarrierShared();
		barrier();
	}
#endif

	if (lid < 32)
	{
#if (BLOCK_SIZE >= 64)
		sData[lid] += sData[lid+32];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 32)
		sData[lid] += sData[lid+16];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 16)
		sData[lid] += sData[lid+8];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 8)
		sData[lid] += sData[lid+4];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 4)
		sData[lid] += sData[lid+2];
		memoryBarrierShared();
#endif
#if (BLOCK_SIZE >= 2)
		sData[lid] += sData[lid+1];
#endif
	}

	if (lid == 0)
	{
		outVector[gl_WorkGroupID.x] = sData[0];
	}
}